//
// Created by denglibin on 19-10-21.
//

/**
 *SIGCHLD信号：子进程结束时父进程会收到该信号
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>

/**
 * 父进程SIGCHLD信号信号处理函数
 * @param signo
 */
void wait_handle(int signo){
    if(signo == SIGCHLD){
        pid_t pid;
        int status;
        while ((pid = waitpid(0, &status, WNOHANG)) > 0){ // 循环 回收多个（可能有多个子进程结束但只收到一次信号）
            printf("waitpid pid is: %d, status is: %d\n", pid, WEXITSTATUS(status));
        }
    }
}

static int main_(){

    int num = 15, i;
    pid_t  pid;
    // 阻塞 SIGCHLD信号 （防止 收到信号时信号处理函数还未设置完成）

    // 定义阻塞信号集(block)
    sigset_t bset, old_set;
    // 清空信号集
    sigemptyset(&bset);
    // 将信号SIGCHLD加入到信号集中
    sigaddset(&bset, SIGCHLD);
    //进行位或操作，将信号集bset更新到进程控制块PCB结构中，阻塞信号
    sigprocmask(SIG_BLOCK, &bset, &old_set);

    for(i = 0; i < num; i++){
        if((pid = fork()) == 0){
            break;
        }
    }
    if(i != num){ // 子进程
        printf("child precess id is %d\n", getpid());
        sigprocmask(SIG_SETMASK, &old_set, NULL);// 还原
        return i+1;
    } else if(i == num){ // 父进程
        // 设置信号处理函数
        struct sigaction new_act, old_act;
        new_act.sa_handler = wait_handle;
        sigemptyset(& new_act.sa_mask);
        new_act.sa_flags = 0;
        sigaction(SIGCHLD, &new_act, &old_act);
        sigprocmask(SIG_SETMASK, &old_set, NULL);// 还原 解除阻塞
        while (1){
            sleep(2);
            //printf("parent pid is:%d\n", getpid());
        }
    }
    return 0;
}